<?php
namespace control;
/**
 * 钉钉回调事件
 */

use control\interfaces;
require_once 'interface.php';
require_once("DingtalkCrypt.php");
class dingCallbackClass
{
    use interfaces;
    private static string $SUITE_KEY;//企业内部应用Appkey
    private static string $TOKEN ;//自定义,与配置项保持一致
    private static string $ENCODING_AES_KEY;//自定义，与配置项保持一致 43位
    private string $signature;
    private int $timeStamp;
    private string $nonce;

    public function __construct()
    {
        self::$SUITE_KEY = para('dingtalkAppKey');
        self::$TOKEN = para('dingtalkCallBackToken');
        self::$ENCODING_AES_KEY = para('dingCallBackAesKey');
        $signature = $this->get('signature')?:'';
        $this->signature = $signature;
        $timeStamp = $this->get('timestamp')?:'';
        $this->timeStamp = $timeStamp;
        $nonce = $this->get('nonce')?:'';
        $this->nonce = $nonce;
        $postdata = file_get_contents("php://input");
        $postList = json_decode($postdata, true);
        $encrypt = $postList['encrypt'];
        $crypt = new DingtalkCrypt(self::$TOKEN, self::$ENCODING_AES_KEY, self::$SUITE_KEY);
        $errCode = $crypt->DecryptMsg($signature, $timeStamp, $nonce, $encrypt, $msg);
        if ($errCode == 0) {
            $this->doEvent($msg);
        }else{
            test('回调解密失败：'.$errCode);
        }
    }

    /**
     * 根据钉钉服务器推送的回调类型做事件处理
     * @param $msg
     */
    public function doEvent($msg)
    {
        $eventMsg = json_decode($msg, true);
        $eventType = $eventMsg['EventType'];
        switch ($eventType) {
            case 'attendance_check_record'://考勤打卡
                //{"DataList":[{"address":"新宇科技_12971","baseMacAddr":"30:AE:A4:40:63:8E","checkTime":1648105846000,"corpId":"dinga7c4eb2b20f0139fffe93478753d9884","locationResult":"Normal","groupId":"ACA54C2C39EAD0F4CD6AC23FB8268CC5","bizId":"A4D9AA276856AA7A04682FDF24999F91","locationMethod":"ATM","checkByUser":true,"deviceName":"新宇科技_12971","deviceSN":"0101BVK180801R012971","userId":"manager2034"}],"EventType":"attendance_check_record"}
                $list = $eventMsg['DataList'];
                if (is_array($list)) {
                    //获取所有食堂的打卡机序列号
                    $hall_deviceNo = [];
                    $all = find(array('table' => 'dining_hall', "where" => "state = '启用'"));
                    foreach ($all['array'] as $array) {
                        if (isset($array['deviceNo'])) {
                            $hall_deviceNo[] = $array['deviceNo'];
                        }
                    }
                    foreach ($list as $array) {
                        $staff = query('staff', "dingtalkId= '$array[userId]'");
                        $checkTime = date('Y-m-d H:i:s', $array['checkTime'] / 1000);
                        if (empty($staff['stid'])) {
                            test("未找到员工,钉钉userId【{$array['userId']}】,打卡时间【" . $checkTime . "】");
                        } elseif (in_array($array['deviceSN'], $hall_deviceNo)) {
                            //食堂内的打卡机，用于取餐
                            $this->takeMeal($staff['stid']);
                        } else {
                            $type = match ($array['locationMethod']) {
                                'USER' => '用户打卡',
                                'ATM' => '钉钉考勤机',
                                'DING_ATM' => '考勤机蓝牙打卡',
                                'BOSS' => '老板改签',
                                'APPROVE' => '审批系统',
                                'SYSTEM' => '考勤系统',
                                'AUTO_CHECK' => '自动打卡',
                                default => $array['locationMethod']
                            };
                            //插入考勤记录表
                            $warn = static::insert(array(
                                "table" => "work_sign",
                                "field" => array(
                                    "jobId" => $staff['jobId'],
                                    "stid" => $staff['stid'],
                                    "dingtalkId" => $staff['dingtalkId'],
                                    "signId" => '',
                                    "signTime" => $checkTime,
                                    "type" => $type,
                                ),
                            ));
                            if ($warn != '新增成功') {
                                test("钉钉打卡回调插入失败,钉钉userId【{$array['userId']}】,打卡时间【" . $checkTime . "】");
                            }
                        }
                    }
                }
                break;
        }
    }

    /**
     * 取餐
     */
    public function takeMeal($stid)
    {
        $staff = query('staff', "stid = '$stid'");
        $hall = query('dining_hall', "member like '%" . $stid . "%'");
        $date = date('Y-m-d');
        $dining_hall_detail = find(array('table' => 'dining_hall_detail', 'where' => "orderId = '$hall[id]' order by list asc"));
        $mealType = '';
        foreach ($dining_hall_detail['array'] as $array) {
            if (time() >= strtotime($date . ' ' . $array['mealStartTime']) && time() <= strtotime($date . ' ' . $array['mealEndTime'])) {
                $mealType = $array['mealType'];
                break;
            }
        }
        $meal_report = query('meal_report', "recordDate = '$date' and hallId = '$hall[id]' and mealType = '$mealType' and staffId = '$stid' and type in ('报餐','代报餐')");
        if (empty($hall['id'])) {
            $this->logSet($stid, $staff['name'] . "不在所有食堂成员中");
        } elseif (empty($mealType) || !in_array($mealType, explode('，', para('mealOption')))) {
            $this->logSet($stid, "当前时间不属于用餐时间");
        } /*elseif (empty($meal_report['id'])) {
            $this->logSet($stid, "未找到您的报餐记录");
        } */elseif (!empty($meal_report['id']) &&$meal_report['workFlow'] == '已取餐') {
            $this->logSet($stid, "您已取餐");
        } else {
            //判断当前时间是否可报餐
            $this->startTrans();
            $id = self::getId();
            $warn = static::insert(array(
                'table' => 'meal_take_record_parent',
                'field' => [
                    'id' => $id,
                    'recordDate' => $date,
                    'hallId' => $hall['id'],
                    'mealType' => $mealType,
                    'stid' =>$staff['stid'],
                ]
            ));
            $bool = static::insert(array(
                'table' => 'meal_take_record',
                'field' => [
                    'id' => self::getId(),
                    'orderId' => $id,
                    'reportId' => $meal_report['id'],
                    'recordDate' => $date,
                    'hallId' => $hall['id'],
                    'mealType' => $mealType,
                    'type' => '取餐',
                    'departmentId' => self::findStaffDepartment($staff['stid'], 'id'),
                    'staffId' => $staff['stid'],
                    'num' => 1,
                    'takeStid' => $staff['stid'],
                ]
            ));
            if ($bool != '新增成功') {
                $warn = '新增取餐记录失败';
            }
            $bool = static::update(array(
                'table' => 'meal_report',
                'field' => [
                    'workFlow' => '已取餐',
                ],
                'where' => "id = '$meal_report[id]'"
            ));
            if ($bool != '更新成功') {
                $warn = '修改取餐状态失败';
            }
            if ($warn == '新增成功') {
                $this->commitTrans();
                $this->logSet($stid, "您在食堂【{$hall['name']}】于【".date('Y-m-d H:i:s')."】成功取得了【{$mealType}】");
            } else {
                $this->rollback();
                $this->logSet($stid, "取餐失败：".$warn);
            }
        }
    }

    /**
     * 写入日志
     * @param $stid
     * @param $text
     * @return string
     */
    public function logSet($stid, $text): string
    {
        $data = [
            'type' => 'my',
            'stid' => $stid,
            'text' => $text,
        ];
        return insert(["table" => "log", "field" => $data]);
    }

    /**
     * 返回success
     * @return string
     */
    public function returnMsg(): string
    {
        $res = "success";
        $crypt = new DingtalkCrypt(self::$TOKEN, self::$ENCODING_AES_KEY, self::$SUITE_KEY);
        $errCode = $crypt->EncryptMsg($res, time(), self::getId(), $encryptMsg);
        if ($errCode !=0){
          test('回调返回消息失败：'.$errCode);
        }
        return $encryptMsg;
    }
}

$obj = new dingCallbackClass();
echo $obj->returnMsg();


